package utils

import (
	"errors"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

// JWT配置
var (
	// JWT密钥，实际项目中应该从配置文件或环境变量读取
	JWTSecret = []byte("bookmark-web-secret-key-2024")
	// Token过期时间
	TokenExpireDuration = time.Hour * 24 // 1天
)

// Claims JWT载荷结构
type Claims struct {
	UserID   uint   `json:"user_id"`
	Username string `json:"username"`
	jwt.RegisteredClaims
}

// GenerateToken 生成JWT令牌
func GenerateToken(userID uint, username string) (string, error) {
	// 创建Claims
	claims := &Claims{
		UserID:   userID,
		Username: username,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenExpireDuration)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
			Issuer:    "bookmark-web",
			Subject:   "user-token",
		},
	}

	// 创建Token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 签名Token
	tokenString, err := token.SignedString(JWTSecret)
	if err != nil {
		return "", err
	}

	return tokenString, nil
}

// ParseToken 解析JWT令牌
func ParseToken(tokenString string) (*Claims, error) {
	// 解析Token
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		// 验证签名方法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, errors.New("无效的签名方法")
		}
		return JWTSecret, nil
	})

	if err != nil {
		return nil, err
	}

	// 验证Token并提取Claims
	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("无效的Token")
}

// ValidateToken 验证JWT令牌（简化版，只返回是否有效）
func ValidateToken(tokenString string) bool {
	_, err := ParseToken(tokenString)
	return err == nil
}

// RefreshToken 刷新JWT令牌
func RefreshToken(tokenString string) (string, error) {
	// 解析原Token
	claims, err := ParseToken(tokenString)
	if err != nil {
		return "", err
	}

	// 检查Token是否即将过期（剩余时间少于1天时可以刷新）
	if time.Until(claims.ExpiresAt.Time) > time.Hour*24 {
		return "", errors.New("Token还未到刷新时间")
	}

	// 生成新Token
	return GenerateToken(claims.UserID, claims.Username)
}

// GetUserIDFromToken 从Token中提取用户ID
func GetUserIDFromToken(tokenString string) (uint, error) {
	claims, err := ParseToken(tokenString)
	if err != nil {
		return 0, err
	}
	return claims.UserID, nil
}

// GetUsernameFromToken 从Token中提取用户名
func GetUsernameFromToken(tokenString string) (string, error) {
	claims, err := ParseToken(tokenString)
	if err != nil {
		return "", err
	}
	return claims.Username, nil
}

// IsTokenExpired 检查Token是否过期
func IsTokenExpired(tokenString string) bool {
	claims, err := ParseToken(tokenString)
	if err != nil {
		return true
	}
	return time.Now().After(claims.ExpiresAt.Time)
}

// GenerateTokenWithExpiry 生成指定过期时间的JWT令牌
func GenerateTokenWithExpiry(userID uint, username string, expiry time.Duration) (string, error) {
	claims := &Claims{
		UserID:   userID,
		Username: username,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(expiry)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
			Issuer:    "bookmark-web",
			Subject:   "user-token",
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(JWTSecret)
}

// GenerateRefreshToken 生成刷新令牌（长期有效）
func GenerateRefreshToken(userID uint, username string) (string, error) {
	// 刷新令牌有效期为30天
	return GenerateTokenWithExpiry(userID, username, time.Hour*24*30)
}

// TokenInfo Token信息结构
type TokenInfo struct {
	UserID    uint      `json:"user_id"`
	Username  string    `json:"username"`
	IssuedAt  time.Time `json:"issued_at"`
	ExpiresAt time.Time `json:"expires_at"`
	IsExpired bool      `json:"is_expired"`
}

// GetTokenInfo 获取Token详细信息
func GetTokenInfo(tokenString string) (*TokenInfo, error) {
	claims, err := ParseToken(tokenString)
	if err != nil {
		return nil, err
	}

	return &TokenInfo{
		UserID:    claims.UserID,
		Username:  claims.Username,
		IssuedAt:  claims.IssuedAt.Time,
		ExpiresAt: claims.ExpiresAt.Time,
		IsExpired: time.Now().After(claims.ExpiresAt.Time),
	}, nil
}
